#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>

template<class T>
class BlockQueue
{
	private:
		int cap;
		pthread_mutex_t lock;
		pthread_cond_t have_space;
		pthread_cond_t have_data;
		std::queue<T> bq;
	private:
		bool IsFull()
		{
			return bq.size() == cap ? true : false;
		}
		bool IsEmpty()
		{
			return bq.size() == 0 ? true : false;
		}
	public:
		BlockQueue(int _cap):cap(_cap)
	{
		pthread_mutex_init(&lock,nullptr);
		pthread_cond_init(&have_space,nullptr);
		pthread_cond_init(&have_data,nullptr);
	}
		void Put(const T& in)
		{
			pthread_mutex_lock(&lock);
			while(IsFull())
			{
				pthread_cond_wait(&have_space,&lock);
			}
			bq.push(in);
			pthread_cond_signal(&have_data);
			pthread_mutex_unlock(&lock);
		}
		void Get(T* out)
		{
			pthread_mutex_lock(&lock);
			while(IsEmpty())
			{
				pthread_cond_wait(&have_data,&lock);
			}
			*out = bq.front();
			bq.pop();

			pthread_cond_signal(&have_space);
			pthread_mutex_unlock(&lock);
		}
		~BlockQueue()
		{
			pthread_mutex_destroy(&lock);
			pthread_cond_destroy(&have_space);
			pthread_cond_destroy(&have_data);
		}

};

